package cz.data.domain.market.service.impl;

import cz.data.domain.market.model.entity.DataApiEntity;
import cz.data.domain.market.service.DataApiManager;
import cz.data.domain.market.service.DataApiService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;

@Component
public class DataApiManagerImpl implements DataApiManager {

    @Lazy
    @Resource
    DataApiService dataApiService;
    @Resource
    RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Override
    public boolean existsApi(DataApiEntity dataApi) {
        String id = dataApi.getId();
        String method = dataApi.getReqMethod();
        String apiVersion = dataApi.getApiVersion();
        String apiUrl = dataApi.getApiUrl();
        return checkDataApi(id, method, apiVersion, apiUrl) || checkServerApi(method, DataApiEntity.buildUrlPath(apiVersion, apiUrl));
    }

    private boolean checkDataApi(String id, String method, String apiVersion, String apiUrl) {
        DataApiEntity api = dataApiService.getDataApiByMethodAndApiUrl(method, apiVersion, apiUrl);
        if (Objects.isNull(api))
            return false;
        return !StringUtils.equals(api.getId(), id);
    }

    private boolean checkServerApi(String method, String apiUrl) {
        RequestMethod requestMethod = RequestMethod.valueOf(method);
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
        return handlerMethods
                .keySet()
                .stream()
                .filter(mappingInfo -> mappingInfo.getDirectPaths().contains(apiUrl))
                .map(RequestMappingInfo::getMethodsCondition)
                .map(RequestMethodsRequestCondition::getMethods)
                .anyMatch(requestMethods -> requestMethods.contains(requestMethod));
    }
}
